﻿using System.Text;
using System.Collections.Generic;
using System;
using Ex03.GarageLogic;

namespace Ex03.GarageManagementSystem.ConsoleUI
{
    public class UserInterface
    {
        public enum eMainOptions
        {
            ListPlateNumbers,
            EnterPlateNumber,
            Exit
        }

        public enum eFilterVehiclesMenu
        {
            Filter,
            NoFilter
        }

        public enum eVehicleFunctionsMenu
        {
            ShowDetails,
            Refuel,
            Recharge,
            InflateWheels,
            ChangeStatus
        }

        public static eMainOptions MainMenu()
        {
            System.Console.Clear();
            string menuTitleStr = "-Main Menu-" + Environment.NewLine + "Please select an option:";

            return (eMainOptions)MenuGenerator.MenuFromEnum(typeof(eMainOptions), menuTitleStr);
        }

        public static void VehiclesInGarageMenu(Garage i_Garage)
        {
            System.Console.Clear();
            string title = "-Show plate numbers of vehicles in the garage-";

            eFilterVehiclesMenu filterChoice = (eFilterVehiclesMenu)MenuGenerator.MenuFromEnum(typeof(eFilterVehiclesMenu), title);
            List<Vehicle> vehicleListToPrint;

            switch (filterChoice)
            {
                case eFilterVehiclesMenu.Filter:
                    vehicleListToPrint = pickVehicleFilter(i_Garage);
                    break;
                case eFilterVehiclesMenu.NoFilter:
                    vehicleListToPrint = i_Garage.Vehicles;
                    break;
                default:
                    throw new Exception("Bad choice reached in menu");
            }

            printVehicleList(vehicleListToPrint);
        }

        private static List<Vehicle> pickVehicleFilter(Garage i_Garage)
        {
            string title = "Filter vehicles by:";
            Vehicle.eVehicleStatusInGarage filter = (Vehicle.eVehicleStatusInGarage)MenuGenerator.MenuFromEnum(typeof(Vehicle.eVehicleStatusInGarage), title);
            List<Vehicle> list = i_Garage.FilterListOfVehicles(filter);

            return list;
        }

        private static void printVehicleList(List<Vehicle> i_VehicleList)
        {
            int i = 1;
            
            if (i_VehicleList.Count == 0)
            {
                Console.WriteLine("No Vehicles Listed.");
            }
            else
            {
                Console.WriteLine("Vehicles List:");
                foreach (Vehicle vehicle in i_VehicleList)
                {
                    Console.WriteLine(i.ToString() + ". " + vehicle.PlateNumber);
                    i++;
                }
            }
            
            MenuGenerator.WaitForKey();
            System.Console.Clear();
        }

        public static void SingleVehicleManipulation(Garage i_Garage)
        {
            Console.Write("Plate Number: ");

            string plateNumberFromUser = Console.ReadLine();
            while (!Vehicle.IsValidPlateNumber(plateNumberFromUser))
            {
                Console.WriteLine("Invalid input, please type a 5-digit plate number:");
                plateNumberFromUser = Console.ReadLine();
            }

            Vehicle vehicle;
            bool vehicleExists = i_Garage.GetVehicle(plateNumberFromUser, out vehicle);

            if (vehicleExists)
            {
                singleVehicleFunctions(ref vehicle);
            }
            else
            {
                System.Console.Clear();
                Console.WriteLine("Not Found... Adding as a new vehicle.");
                addNewVehicle(i_Garage, plateNumberFromUser);
            }
        }

        private static void singleVehicleFunctions(ref Vehicle io_Vehicle)
        {
            System.Console.Clear();
            string menuTitleStr = io_Vehicle.PlateNumber.ToString() + " Found!" + System.Environment.NewLine + "Please select an option:";
            eVehicleFunctionsMenu userSelection = (eVehicleFunctionsMenu)MenuGenerator.MenuFromEnum(typeof(eVehicleFunctionsMenu), menuTitleStr);

            switch (userSelection)
            {
                case eVehicleFunctionsMenu.ShowDetails:
                    System.Console.Clear();
                    Console.WriteLine(io_Vehicle.ToString());
                    break;
                case eVehicleFunctionsMenu.Refuel:
                    refuelVehicle(ref io_Vehicle);
                    break;
                case eVehicleFunctionsMenu.Recharge:
                    rechargeVehicle(ref io_Vehicle);
                    break;
                case eVehicleFunctionsMenu.InflateWheels:
                    io_Vehicle.InflateAllWheels();
                    Console.WriteLine("Wheels successfuly inflated!");
                    break;
                case eVehicleFunctionsMenu.ChangeStatus:
                    changeVehicleStatus(ref io_Vehicle);
                    break;
                default:
                    throw new Exception("Invalid enum");
            }

            MenuGenerator.WaitForKey();
        }

        private static void changeVehicleStatus(ref Vehicle io_Vehicle)
        {
            Vehicle.eVehicleStatusInGarage newStatus = (Vehicle.eVehicleStatusInGarage)MenuGenerator.MenuFromEnum(typeof(Vehicle.eVehicleStatusInGarage), "Pick a new status:");

            io_Vehicle.CurrentStatusInGarage = newStatus;

            Console.WriteLine("Status successfuly changed to {0}!{1}", newStatus.ToString(), Environment.NewLine);
        }

        private static void rechargeVehicle(ref Vehicle io_Vehicle)
        {
            IElectricBased electricVehicle = io_Vehicle as IElectricBased;
            float hoursToAdd;

            if (electricVehicle != null)
            {
                hoursToAdd = MenuGenerator.GetFloatFromUser("How many hours should be added?");

                bool validInput = false;
                while (!validInput)
                {
                    validInput = true;
                    try
                    {
                        electricVehicle.Recharge(hoursToAdd, ref io_Vehicle);
                    }
                    catch (ValueOutOfRangeException valueException)
                    {
                        validInput = false;
                        Console.WriteLine(valueException.ToString());
                        hoursToAdd = MenuGenerator.GetFloatFromUser("Enter how many hours:");
                    }
                }

                Console.WriteLine(hoursToAdd + " Hours added...");
            }
            else
            {
                Console.WriteLine("This is not an electric based vehicle, sorry.");
            }
        }

        private static void refuelVehicle(ref Vehicle io_Vehicle)
        {
            IFuelBased fuelVehicle = io_Vehicle as IFuelBased;
            FuelEngine.eFuelType k_FuelType;
            float litresToAdd;

            if (fuelVehicle != null)
            {
                k_FuelType = (FuelEngine.eFuelType)MenuGenerator.MenuFromEnum(typeof(FuelEngine.eFuelType), "Pick a fuel type:");
                litresToAdd = MenuGenerator.GetFloatFromUser("How many literes should be added?");

                bool validInput = false;
                while (!validInput)
                {
                    validInput = true;
                    try
                    {
                        fuelVehicle.Refuel(litresToAdd, k_FuelType, ref io_Vehicle);
                    }
                    catch (ValueOutOfRangeException valueException)
                    {
                        validInput = false;
                        Console.WriteLine(valueException.ToString());
                        litresToAdd = MenuGenerator.GetFloatFromUser("How many literes should be added?");
                    }
                    catch (ArgumentException wrongFuel)
                    {
                        validInput = false;
                        if (wrongFuel.ParamName == "i_FuelType")
                        {
                            Console.WriteLine("This isn't the currect fuel type, sorry. try : " + fuelVehicle.FuelPowerSource.FuelType.ToString());
                            k_FuelType = (FuelEngine.eFuelType)MenuGenerator.MenuFromEnum(typeof(FuelEngine.eFuelType), "Pick a fuel type:");
                        }
                        else
                        {
                            throw;
                        }
                    }
                }

                Console.WriteLine(litresToAdd + " Liters added...");
            }
            else
            {
                Console.WriteLine("This is not an fuel based vehicle, sorry.");
            }
        }

        private static void addNewVehicle(Garage i_Garage, string i_PlateNumberFromUser)
        {
            string menuTitleStr = "-New Vehicle-" + Environment.NewLine + "Please select an option:";
            Factory.eVehicleTypesSupported userVehicleTypeSelection = (Factory.eVehicleTypesSupported)MenuGenerator.MenuFromEnum(typeof(Factory.eVehicleTypesSupported), menuTitleStr);
            
            Vehicle newVehicle = Factory.MakeVehicle(userVehicleTypeSelection);
            Dictionary<string, string> vehicleDictionary = newVehicle.CreateForm();

            newVehicle.PlateNumber = i_PlateNumberFromUser;
            
            Console.WriteLine("-Please enter info-");
            MenuGenerator.FillOutDictionary(ref vehicleDictionary);

            bool validInput = false;
            while (!validInput)
            {
                try
                {
                    validInput = true;
                    newVehicle.ParseFields(vehicleDictionary);
                }
                catch (System.ArgumentException argEx)
                {
                    validInput = false;
                    vehicleDictionary[argEx.Message] = null;

                    Console.WriteLine(argEx.Message + " has an invalid value. Please try again:");
                    MenuGenerator.FillOutDictionary(ref vehicleDictionary);
                }
                catch (System.FormatException formatEx)
                {
                    validInput = false;
                    vehicleDictionary[formatEx.Message] = null;
                    Console.WriteLine(formatEx.Message + " is not properly formatted. Please try again:");
                    MenuGenerator.FillOutDictionary(ref vehicleDictionary);
                }
                catch (ValueOutOfRangeException valEx)
                { 
                    validInput = false;
                    vehicleDictionary[valEx.Message] = null;
                    Console.WriteLine(valEx.Message + " - Value must be between [" + valEx.MinValue + "," + valEx.MaxValue + "]. Please try again:" );
                    MenuGenerator.FillOutDictionary(ref vehicleDictionary);
                }
            }

            i_Garage.Vehicles.Add(newVehicle);
        }
    }
}
